package rexsee.multimedia;

import java.lang.reflect.Method;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.Json;
import rexsee.core.utilities.RexseeClazz;
import rexsee.core.utilities.Utilities;
import rexsee.multimedia.CameraPreviewDialog.OnCameraPreviewKeyDown;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.view.KeyEvent;

public class RexseeCameraPreview implements JavascriptInterface {

	public static final String INTERFACE_NAME = "CameraPreview";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeCameraPreview(childBrowser);
	}

	public static final String EVENT_ONCAMERASTARTED = "onCameraStarted";
	public static final String EVENT_ONCAMERAZOOMFINISHED = "onCameraZoomFinished";
	public static final String EVENT_ONCAMERAPREVIEWKEYDOWN = "onCameraPreviewKeyDown";

	public static final String CAMERA_NOTSTARTED = "Carmera preview is not started.";

	public static RexseeCameraPreview getPreview(Browser browser) {
		RexseeCameraPreview preview = (RexseeCameraPreview) browser.interfaceList.get(browser.application.resources.prefix + INTERFACE_NAME);
		if (preview == null) return null;
		if (preview.getCamera() == null) return null;
		return preview;
	}
	public static String _getSupportedArguments(Camera camera) {
		Camera.Parameters paras = camera.getParameters();
		String result = "";
		try {
			Method method;
			//result += "\"maxExposureCompensation\":" + paras.getMaxExposureCompensation(); //2.2+
			method = Camera.Parameters.class.getMethod("getMaxExposureCompensation");
			result += "\"maxExposureCompensation\":" + method.invoke(paras);
			//result += ",\"minExposureCompensation\":" + paras.getMinExposureCompensation(); //2.2+
			method = Camera.Parameters.class.getMethod("getMinExposureCompensation");
			result += ",\"minExposureCompensation\":" + method.invoke(paras);
			//result += ",\"exposureCompensationStep\":" + paras.getExposureCompensationStep(); //2.2+
			method = Camera.Parameters.class.getMethod("getExposureCompensationStep");
			result += ",\"exposureCompensationStep\":" + method.invoke(paras);
		} catch (Exception e) {
		}
		result += ",\"sceneMode\":" + Json.toJson(paras.getSupportedSceneModes());
		result += ",\"focusMode\":" + Json.toJson(paras.getSupportedFocusModes());
		result += ",\"flashMode\":" + Json.toJson(paras.getSupportedFlashModes());
		result += ",\"colorEffect\":" + Json.toJson(paras.getSupportedColorEffects());
		result += ",\"antibanding\":" + Json.toJson(paras.getSupportedAntibanding());
		result += ",\"whiteBalance\":" + Json.toJson(paras.getSupportedWhiteBalance());
		return "{" + result + "}";
	}
	public static int _getFormat(String formatString) {
		if (formatString.equalsIgnoreCase("JPEG")) return 256;//ImageFormat.JPEG, for 2.1-
		else if (formatString.equalsIgnoreCase("NV16")) return 16;//ImageFormat.NV16, for 2.1-
		else if (formatString.equalsIgnoreCase("NV21")) return 17;//ImageFormat.NV21, for 2.1-
		else if (formatString.equalsIgnoreCase("RGB_565")) return 4; //ImageFormat.RGB_565, for 2.1-
		else if (formatString.equalsIgnoreCase("YUY2")) return 20; //ImageFormat.YUY2, for 2.1-
		else return 256;//ImageFormat.JPEG, for 2.1-
	}
	public static String _getFormat(int formatInt) {
		String format;
		switch (formatInt) {
			case 256 : //ImageFormat.JPEG
				format = "JPEG";
				break;
			case 16 : //ImageFormat.NV16
				format = "NV16";
				break;
			case 17 : //ImageFormat.NV21
				format = "NV21";
				break;
			case 4 : //ImageFormat.RGB_565
				format = "RGB_565";
				break;
			case 20 : //ImageFormat.YUY2
				format = "YUY2";
				break;
			default :
				format = "UNKOWON";
				break;
		}
		return format;
	}
	public static String _getArguments(Camera camera) {
		Camera.Parameters paras = camera.getParameters();
		int formatInt = paras.getPreviewFormat();
		Size previewSize = camera.getParameters().getPreviewSize();
		String result = "";
		try {
			Method method;
			//result += "\"focalLength\":" + paras.getFocalLength();
			method = Camera.Parameters.class.getMethod("getFocalLength");
			result += "\"focalLength\":" + method.invoke(paras);
			//result += ",\"horizontalViewAngle\":" + paras.getHorizontalViewAngle();
			method = Camera.Parameters.class.getMethod("getHorizontalViewAngle");
			result += ",\"horizontalViewAngle\":" + method.invoke(paras);
			//result += ",\"verticalViewAngle\":" + paras.getVerticalViewAngle();
			method = Camera.Parameters.class.getMethod("getVerticalViewAngle");
			result += ",\"verticalViewAngle\":" + method.invoke(paras);
			//result += ",\"exposureCompensation\":" + paras.getExposureCompensation();
			method = Camera.Parameters.class.getMethod("getExposureCompensation");
			result += ",\"exposureCompensation\":" + method.invoke(paras);
		} catch (Exception e) {
		}
		result += ",\"sceneMode\":\"" + paras.getSceneMode() + "\"";
		result += ",\"focusMode\":\"" + paras.getFocusMode() + "\"";
		result += ",\"flashMode\":\"" + paras.getFlashMode() + "\"";
		result += ",\"colorEffect\":\"" + paras.getColorEffect() + "\"";
		result += ",\"antibanding\":\"" + paras.getAntibanding() + "\"";
		result += ",\"whiteBalance\":\"" + paras.getWhiteBalance() + "\"";
		result += ",\"previewFormat\":\"" + _getFormat(formatInt) + "\"";
		result += ",\"previewWidth\":" + previewSize.width;
		result += ",\"previewHeight\":" + previewSize.height;
		result += ",\"previewFrameRate\":" + paras.getPreviewFrameRate();
		return "{" + result + "}";
	}

	public final Context mContext;
	private final Browser mBrowser;
	public CameraPreviewDialog previewDialog = null;

	public RexseeCameraPreview(Browser browser) {
		mBrowser = browser;
		mContext = browser.getContext();
		mBrowser.eventList.add(EVENT_ONCAMERASTARTED);
		mBrowser.eventList.add(EVENT_ONCAMERAZOOMFINISHED);
		mBrowser.eventList.add(EVENT_ONCAMERAPREVIEWKEYDOWN);
	}

	public Camera getCamera() {
		return (previewDialog == null) ? null : previewDialog.camera;
	}

	//JavaScript Interface
	public boolean start(String style, final int orientation) {
		if (previewDialog != null) return true;
		if (orientation != 0 && orientation != 90 && orientation != 180 && orientation != 270) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), "Invalid orientation.");
			return false;
		}
		previewDialog = new CameraPreviewDialog(mBrowser, style);
		previewDialog.start(orientation, new Runnable() {
			@Override
			public void run() {
				mBrowser.eventList.run(EVENT_ONCAMERASTARTED);
			}
		}, new OnCameraPreviewKeyDown() {
			@Override
			public void run(int keyCode) {
				if (keyCode == KeyEvent.KEYCODE_BACK && previewDialog.styleSheet.window_cancelable.equalsIgnoreCase("true")) {
					stop();
				} else {
					mBrowser.eventList.run(EVENT_ONCAMERAPREVIEWKEYDOWN, new String[]{String.valueOf(keyCode)});
				}
			}
		});
		return true;
	}
	public boolean stop() {
		if (previewDialog != null) {
			previewDialog.dismiss();
			previewDialog = null;
		}
		return true;
	}
	public void show() {
		if (previewDialog == null) return;
		((Activity) mContext).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				previewDialog.show();
			}
		});
	}

	public boolean zoom(int value) {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		return previewDialog.zoom(value);
	}
	public boolean zoomIn() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		return previewDialog.zoomIn();
	}
	public boolean zoomOut() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		return previewDialog.zoomOut();
	}
	public boolean isSmoothZoomSupported() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		return previewDialog.isSmoothZoomSupported();
	}
	public boolean isZoomSupported() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		return previewDialog.isZoomSupported();
	}
	public int getMaxZoom() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return -1;
		}
		return previewDialog.getMaxZoom();
	}
	public int getCurrentZoom() {
		if (previewDialog == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return -1;
		}
		return previewDialog.getCurrentZoom();
	}

	public boolean setArguments(String arguments) {
		if (getCamera() == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), CAMERA_NOTSTARTED);
			return false;
		}
		if (arguments == null || arguments.equals("")) return true;
		String[] argus = arguments.split(";");
		Camera camera = getCamera();
		Camera.Parameters paras = camera.getParameters();
		int pWidth = -1, pHeight = -1;
		for (int i = 0; i < argus.length; i++) {
			if (argus[i].indexOf("=") <= 0) continue;
			String key = argus[i].substring(0, argus[i].indexOf("=")).trim();
			String value = argus[i].substring(argus[i].indexOf("=") + 1).trim();
			try {
				if (key.equalsIgnoreCase("exposureCompensation")) {
					int v = Utilities.getInt(value, -1);
					if (v > 0) {
						//paras.setExposureCompensation(v); not support for 2.1-
						try {
							Method method = RexseeClazz.getMethod(Camera.Parameters.class, "setExposureCompensation");
							if (method != null) method.invoke(paras, new Object[]{v});
						} catch (Exception e) {
							mBrowser.exception(getInterfaceName(), "Can not find method setExposureCompensation.");
						}
					}
				} else if (key.equalsIgnoreCase("sceneMode")) {
					paras.setSceneMode(value);
				} else if (key.equalsIgnoreCase("focusMode")) {
					paras.setFocusMode(value);
				} else if (key.equalsIgnoreCase("flashMode")) {
					paras.setFlashMode(value);
				} else if (key.equalsIgnoreCase("colorEffect")) {
					paras.setColorEffect(value);
				} else if (key.equalsIgnoreCase("antibanding")) {
					paras.setAntibanding(value);
				} else if (key.equalsIgnoreCase("whiteBalance")) {
					paras.setWhiteBalance(value);
				} else if (key.equalsIgnoreCase("previewFormat")) {
					paras.setPreviewFormat(_getFormat(value));
				} else if (key.equalsIgnoreCase("previewWidth")) {
					pWidth = Utilities.getInt(value, -1);
				} else if (key.equalsIgnoreCase("previewHeight")) {
					pHeight = Utilities.getInt(value, -1);
				} else if (key.equalsIgnoreCase("previewFrameRate")) {
					int v = Utilities.getInt(value, -1);
					if (v > 0) paras.setPreviewFrameRate(v);
				}
			} catch (Exception e) {
			}
		}
		try {
			if (pWidth > 0 && pHeight > 0) paras.setPreviewSize(pWidth, pHeight);
			camera.setParameters(paras);
			return true;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public String getArguments() {
		if (getCamera() != null) {
			return _getArguments(getCamera());
		} else {
			try {
				Camera c = Camera.open();
				String rtn = _getArguments(c);
				c.release();
				c = null;
				return rtn;
			} catch (Exception e) {
				mBrowser.exception(getInterfaceName(), e);
				return "{}";
			}
		}
	}
	public String getSupportedArguments() {
		if (getCamera() != null) {
			return _getSupportedArguments(getCamera());
		} else {
			try {
				Camera c = Camera.open();
				String rtn = _getSupportedArguments(c);
				c.release();
				c = null;
				return rtn;
			} catch (Exception e) {
				mBrowser.exception(getInterfaceName(), e);
				return "{}";
			}
		}
	}

}
